Designing a FOSS Controller

Table of Contents
Control has a problem with proprietary software. It’s not just that I would personally prefer free and open options, but there are real issues with the current state of control engineering tools, and some could be improved by open source software.
The thing about controllers is, that they are everywhere. You might not realize this, because we are so used to everyday technology that we take it for granted. On occasions, we see the wonders of advanced tech, like when we talk about autonomous cars or an amazing landing of a spacecraft, but the true achievements are often hidden in the production chain. Efficient production of high-tech goods are made possible by crazy machines like the ones manufacturing chips.
Many of those projects rely on controllers. We need good controllers.
How controllers are made #
Not all control problems are made equal. There are easy problems, that can be solved by slapping a PID controller on whatever hardware you are working on, test it a few times and call it a day. Surely this is not possible for safety critical systems, but these controllers can be implemented using almost no knowledge or software equipment.
Good and reliable controllers, however, require background knowledge and meticulous work. They need strong software to aid design and assure quality by simulations and theoretical stability verification. They require MATLAB©. Right? Of course not.
Our beloved MATLAB #
The proprietary software monolith, that is MATLAB, is to control and simulation engineers what Microsoft Office is for offices. Sure, there are some alternatives, but you look stupid if you try to use them on a professional level. Why would you abandon a proven software package, that has been tested again and again, has been in professional use for ages and has everything you need?
If you are tasked with designing a robust airplane controller these questions need a good answer. If it crashes, you cannot just open a GitHub issue at the open source alternative whose obscure bug caused the death of a hundred people. When your answer to “why is my son dead” is that a hobby programmer made a mistake on his sunday afternoon FOSS session, you will not stay in business for long.
Fortunately, not every control problem contains an airplane. For smaller projects with less risk, it is indeed worthwhile to delve into alternatives to MATLAB. Not because of FOSS philosophy, but because of money. MATLAB is expensive. Very expensive. A year of MATLAB is about €900, which may not be much for big companies in comparison to the cost of personnel, but for learners, projects in between jobs and hobbyists it is. At least it is enough money to take a look at the alternatives.
Oh, and by the way, there are many more reasons why people try to avoid MATLAB. It is a big, old, clunky software, that has a lot of quirks, crashes way to often and can be a pain to install on non-windows systems. Big projects end up in a mess of small files, which need to be sorted and refactored by an intern. The day job engineers get accustomed to these things, but if there should be a better alternative, many will consider it.
Where is the FOSS MATLAB clone? #
FOSS shines at its brightest in applications that are used by FOSS developers. Specialized software that has no use for developers on the other hand has a much more difficult stance. The software we want – a better FOSS MATLAB – needs to be highly reliable, fast and useable by people with little developing and programming experience. Algorithms to design controllers are complicated, often require a lot of math and control theory to be understood and produce stable numerics. In order to develop such a tool, one need to know system theory, numerical computations and of course software engineering skills. Those people are rare.
But they do exist. They have to exist, otherwise MATLAB could never have been built. There are just these people, creating their own drop-in replacement for MATLAB, which they call GNU Octave.
This project has a long history and can be used for a lot of projects. Its language uses the same syntax as MATLAB up to some minor details rarely encountered. Many important algorithms have been implemented, external libraries integrated and due to its modularity, it starts up much faster than MATLAB. Want to do a quick matrix calculation? Just open the Octave terminal and start typing. No need to wait until your laptop has started MATLAB.
But the devil is in the details.
The GUI of Octave is minimal, which enables a quick startup
but often is not enough for engineers that are not used to doing
everything in code.
Want to use a specific ODE solver?
Fixed step like Forward Euler with a specific step size?
Something similar to MATLABs ode113
?
Go read the documentation how to code that.
“Oh”, you say, “which documentation?” Or to say it in the words of the Octave wiki:
The interpreter is written in C++, undocumented. There are many possible projects associated with it.
The few people behind GNU Octave are working hard to implement the still missing features, that MATLAB provides. Documentation is lacking a bit, especially in older parts of the code base. Some of this can be excused, because you can just go and read the documentation of MATLAB. Octave is similar enough that a lot of MATLAB code can be executed with little to no modifications. The subtle differences can be read in the documentation of Octave. But without rigorous documentation, a program which has practically no GUI is hard to learn for non-programmers.
To sum my argument about GNU Octave up: It is a mess. A working mess, mind you! If you have the time to look some things up, Octave is very much capable of doing MATLABs job, unless the problem is getting too advanced. If you are an advanced MATLAB user, chances are you will encounter a routine not yet implemented and have to do it yourself. But otherwise, this is a real, close alternative to MATLAB. However, Octave cannot overcome some of the issues MATLAB has itself. Why try to replicate the working mess that MATLAB is, when you can try to improve?
What makes Software great #
Software is changing all the time. We find newer, more efficient ways to do something and it’s annoying when people don’t switch to the obviously better alternative. But enough convenience behind it, people switch.
The reason MATLAB became successful in the fist place is convenience. It bundled all the different libraries together, connected through a clean interface that is easy to use. Nobody wants to do matrix vector calculations in C++. But the efficient optimization algorithm is written in it. And then there is the proven linear algebra library written in Fortran that you want to use. Sounds tedious? Well with MATLAB you can use those libraries with a interpreter language. You don’t need to be a software expert to use this. A control expert can use this too!
Or a student. MathWorks, the company behind MATLAB managed to get its software so deep into universities, that it is the first and only solution for simulation that the students will encounter in a while. The professors like MATLAB, because they saw it evolve and adapt the new research in their field. Plus the industry uses it, so it is a convenient way to stay in couch with the jobs their students will apply for, while the professors will stay in academia. They know how much hassle it used to be, to get all the necessary software libraries together. A programmer might not have struggled with a C++ wrapper of a Fortran library, but academia has.
My point is, that the combination of software packages creates astounding results. Interoperability is key. Staying in touch with new research is key. Easy usage is key. And all this reminds me of another interpreter language.
Only a few programming languages have such a large pool of libraries as Python. You can do everything in Python. Whatever your problem is, there is a Python package in the pip repository. So what about controller design?
My journey with the Python Control Systems Library #
For me the choice is obvious. Sure, I could look at Octave or other alternatives, but as I’m already very familiar with Python and Numpy, looking at a Python solution was my first idea. I googled and chose a library with the intention of applying it on a simple problem.
The challenge for myself was to build a pole placement based observer and controller for a simple SISO LTI system with two unstable poles. This is very standard approach and should be easy enough, or at least I thought so.
Installation is trivial, if you have done anything with Python before. The only thing you need to know is, that some features additionally depend on slycot, a wrapper for routines involving specific kinds of equations.
Building the dynamical system to control is easy, if you are somewhat familiar with system theory.
import control as ct
A = [[0, 1], [-1, 2]]
B = [[0], [1]]
C = [[1, 0]]
D = [[0]]
sys = ct.ss(A, B, C, D)
This creates a state space (ss) representation of the system, i.e., a linear differential matrix equation. Like the following:
$$\dot{x} = Ax + Bu$$
with an output equation
$$y = Cx + Du,$$
but the details are not important.
Important is, that I can do all this in a nice Jupyter notebook, which is an interactive working environment perfect for such tasks as adjusting some parameters. It enables breaking up the code in cells which can contain explaining text or a piece of code.

My plots are shown directly under the relevant code section, so it’s tidier than the pop-ups that are the standard MATLAB experience. Of course MATLAB has a similar feature (so-called live scripts), but their notebooks are stored in a binary format, which interferes with any sane version control setup. People have been complaining about this for a long time, but MathWorks does not seem to care. Jupyter notebooks are thus a huge plus for using the Python control systems library.
I am happy. Building the controller was easy, all my beloved functions from MATLAB are available, albeit with Python syntax.
K = ct.place(A, B, [-1, -5])
But then the issue arises: How do I connect all my designed elements? How does the observer tell the controller the estimated states? The connections are missing.
To understand how big the difference is, we have to talk about the MATLAB feature Simulink. Well, it is more than just a feature. It is a miracle.
Missing Simulink #
Control engineers think in block diagrams. Every book and research paper shows the setup in a diagram, which contains different elements, all nicely labeled and understandable in an instant. We can see connections and understand what is happening. Breaking the linearity of code helps to visualize the feedback – the most important part of this operation. Feedback systems are not a linear chain of events or elements. This property is why they work in the first place.
Block diagrams are not difficult. Take this one for example, featuring a simpel but very typical setup:

Simulink is a graphical interface to connect blocks with lines representing signals. Thus, a setup is described exactly in the form the engineer imagines it. There is no coding involved, you just connect those blocks by dragging your mouse.
Of course this graphical way has its downsides. Version control is limited, some little quirks have to be accepted. All in all, however, it is a strong tool and very useful for people who are rather control engineers than programmers.
Connecting Signals in Python #
In Python, we have to do all of this with code. It is not the first time I have done this, as MATLAB of course also has the option to use code instead of Simulink. Especially when working with robust control, there is a second method that is acceptable in difficulty:
You name the signals. Every connection gets a name and when the name of an output matches the name of an input, that is a connection. In Python with the system from above, this means we write
sys = ct.ss(A, B, C, D, inputs="u", outputs="y")
which is easy enough. Now we just have to make sure, the output of the controller is ´u´ and it will be connected to our system. So what could go wrong there?
Dimensions are Difficult #
The first time I coded the pole placement observer and controller this did not work for me. It took me some time to debug until I found the issue. Of course, it were signal dimensions. Although not the way I would have thought.
In control, signals are often multidimensional, meaning it contains multiple scalar signals. $$ u = \begin{bmatrix} u_1 & u_2 & \cdots & u_m \end{bmatrix}^\top $$ I’ve had problems managing signal dimensions in MATLAB too. If I recall correctly, it was a sumblock, which did not recognize the right signal dimension, so when I encountered a similar problem using the Python Control Systems Toolbox, I made sure to tell the sumblock what dimension my signal was.
Ironically, this was the issue messing my interconnection up. Apparently, when you do this
sumblk = ct.summing_junction(inputs=["r", "-y"], output="e", dimension=1)
and explicitly state the signal dimension, then the toolbox behaves differently from leaving the dimension unspecified. I honestly don’t completely understand what happened there, but
sumblk = ct.summing_junction(inputs=["r", "-y"], output="e")
worked like a charm.
The last problem was, that I incorrectly remembered how to do a pole placement observer. The correct formula is
L = (ct.place(A.T, C.T, obsv_poles)).T
but I forgot to transpose the A matrix. With that settled, I got my working controller without too much hassle.
Conclusion #
Truthfully, I expected more issues when starting this challenge. It may be, that difficulties arise when applying more complicated setups or that I was lucky, but to me, it seems that Python is fit to design controllers. MATLAB is not the only way we can do this and for me, this means it is not worth to pay or pirate MATLAB just to design a controller or work on a hobby project. Concerning large scale and professional settings, it remains to be seen how well Python can fulfill expectations, but for simple pole placement observers and controllers, Python is ready.